<script setup lang="ts">
import {ElPagination} from "element-plus";
import {nextTick, onMounted, type PropType, reactive, ref} from "vue";
import {LoadFunction, TableColumn} from "./types";
import {Filter, RefreshRight,Loading} from "@element-plus/icons-vue";

const props = defineProps({
  columns:Object as PropType<TableColumn[]>,
  query:Object as any,
  loadFunction:Function as PropType<LoadFunction>,
  autoLoad:{
    type:Boolean,
    default: true,
  },
  useSelect:{
    type:Boolean,
    default: false,
  },
  selectType:{
    type:String as PropType<'checkbox'|'radio'>,
    default:'checkbox'
  },
  pageSizes:{
    type:Array as PropType<Array<number>>,
    default:()=>[50,100,200,300]
  },
  title:String,
  size:{
    type:String as PropType<'' | 'large' | 'default' | 'small'>,
    default: 'large'
  },
  border:{
    type:Boolean,
    default:false
  }
});
const pageQuery=reactive<any>({
  pageSize:50,
  pageNo:1
})
const pushQuery=(q:any,c:TableColumn)=>{
  c._filter=q
  nextTick(()=>{
    loadData()
  })
}
const removeQuery=(c:TableColumn)=>{
  c._filter=undefined
  nextTick(()=>{
    loadData()
  })
}
const loading=ref(false)
const pageResult=ref<PageResult<any>>()
const loadData=async ()=>{
  if (props.loadFunction){
    loading.value=true;
    //对所有字段进行收集
    const mergedObject = Object.assign({}, ...(props.columns?.map(c => c._filter) || []));
    const q={...pageQuery,...props.query,...mergedObject}
    console.log(`条件搜索: ${JSON.stringify(q)}`)
    const res=await props.loadFunction(q)
    if (Array.isArray(res)){
      pageResult.value={list:res,total:-1} as PageResult<any>;
    }else {
      pageResult.value = res;
    }
    loading.value=false;
  }
}
const selectedRows=ref<any[]>([])
const selectedRow=ref<any>()

const selectRow=(row)=>{
  console.log('selectRow',row)
  if (props.selectType==='checkbox'){
    row._selected=!(row._selected||false);
    if (row._selected){
      selectedRows.value.push(row)
    }else {
      selectedRows.value=selectedRows.value.filter(r=>r!==row)
    }
  }else {
    selectedRow.value=row
  }
}
const getSelected=()=>{
  if (props.selectType==='checkbox'){
    return selectedRows.value
  }else {
    return selectedRow.value
  }
}
const setSelected=(data:any|any[])=>{
  if (Array.isArray(data)){
    selectedRows.value=data
  }else {
    selectedRow.value=data
  }
}
const reload=()=>{
  nextTick(()=>{
    loadData()
  })
}
onMounted(()=>{
  if (props.autoLoad){
    loadData()
  }
})
defineExpose({
  reload,
  getSelected,
  setSelected
})
</script>

<template>
  <div style="width:100%;height:100%;">
    <div class="table-header" :class="props.border?'border':''">
      <div class="title">
        <span>{{props.title}}</span>
        <el-button link type="info" text @click="reload()">
          <el-icon>
            <Loading v-if="loading"/>
            <RefreshRight v-else/>
          </el-icon>
        </el-button>
      </div>
      <slot name="tools"></slot>
    </div>
    <div class="table-body" v-loading="loading">
      <el-table  :border="props.border" :size="props.size" style="height: 100%" :data="pageResult?.list||[]" :stripe="true" :show-overflow-tooltip="true">
        <template v-if="props.useSelect">
          <el-table-column width="80" :fixed="'left'">
            <template #default="scope">
              <template v-if="props.selectType==='checkbox'">
                <el-checkbox :model-value="scope.row._selected" @click="selectRow(scope.row)"/>
              </template>
              <template v-else>
                <el-radio-group :model-value="selectedRow?.id"  @click="selectRow(scope.row)">
                  <el-radio :value="scope.row.id"/>
                </el-radio-group>
              </template>
            </template>
          </el-table-column>
        </template>
        <el-table-column v-for="c in props.columns" :key="c.prop" v-bind="c">
          <template   #default="scope">
            <template v-if="c.slot!=undefined">
              <slot :name="c.slot" v-bind="scope"></slot>
            </template>
            <template v-else-if="c.formatter">
              <component :is="c.formatter(scope.row,scope.column,scope.$index)"/>
            </template>
            <template v-else>
              {{scope.row[scope.column.property]}}
            </template>
          </template>
          <template #header="scope">
            <div class="table-header-inner">
              <span style="font-size: 15px">{{scope.column.label}}</span>
              <el-popover
                  v-if="c.useFilter"
                  placement="bottom-start"
                  :width="200"
                  trigger="click"
              >
                <template #default>
                  <el-form-core :form-items="c.queryForms" @ok="q=>{pushQuery(q,c)}" @cancel="removeQuery(c)"/>
                </template>
                <template #reference>
                  <span class="_icon"><el-icon :size="15"><Filter /></el-icon></span>
                </template>
              </el-popover>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <div class="table-footer" :class="props.border?'border':''">
      <el-pagination :layout="'total,prev, pager, next,slot, jumper'" :total="pageResult?.total||0"
                     v-model:page-size="pageQuery.pageSize"
                     v-model:current-page="pageQuery.pageNo" @change="reload">
        <template #default>
          <div style="padding: 0 0 0 15px">
            <el-select v-model="pageQuery.pageSize" @change="reload">
              <template #prefix>
                条数
              </template>
              <el-option v-for="n in props.pageSizes" :value="n" :key="n" :label="n"/>
            </el-select>
          </div>
        </template>
      </el-pagination>
    </div>
  </div>
</template>

<style scoped lang="scss">
.table-header{
  height: 50px;
  display: flex;
  flex-direction: row;
  gap: 10px;
  align-items: center;
  background-color: var(--el-bg-color-overlay);
  padding: 0 20px;
  border-radius: 10px 10px 0 0;
  .title{
    font-size: 18px;
    font-weight: bold;
    flex: 1;
    gap: 10px;
    display: flex;
    flex-direction: row;
  }
}
.table-header.border{
  border: 1.5px solid hsl(var(--border));
  border-bottom: none;
}
.table-footer{
  height: 50px;
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  background-color: var(--el-bg-color-overlay);
  padding:0 20px;
  border-radius: 0 0 10px 10px;
}
.table-footer.border{
  border: 1.5px solid hsl(var(--border));
  border-top: none;
}
.table-body{
  height: calc(100% - 100px);
  overflow: hidden;
}
.table-header-inner{
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  user-select: none;
  ._icon{
    height: 18px;
    margin: 0 5px;
    cursor: pointer;
  }
  ._icon:hover{
    color: var(--left-menu-bg-active-color);
  }
}
</style>
